/*
 * TMap Designer - A Thematic Map design software
 * Copyright (C) 2006 World Health Organization
 * http://www.who.int
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
 */
package who.tmap.dao.impl;

import java.io.File;
import java.util.Map;
import java.util.TreeMap;

import org.jdom.Attribute;
import org.jdom.Element;

import who.tmap.bo.Annotations;
import who.tmap.bo.Attrs;
import who.tmap.bo.BaseMap;
import who.tmap.bo.BizObject;
import who.tmap.bo.BizObjects;
import who.tmap.bo.ThematicMap;
import who.tmap.bo.cd.CDTypes;
import who.tmap.bo.cd.CartographicDisplay;
import who.tmap.bo.impl.BizObjectFactory;
import who.tmap.dao.AnnotationsDAO;
import who.tmap.dao.BaseMapDAO;
import who.tmap.dao.DataDAO;
import who.tmap.dao.TMapDAOException;
import who.tmap.dao.ThematicMapDAO;
import who.tmap.dao.cd.CartographicDisplayDAO;
import who.tmap.dao.cd.impl.CDDAOFactory;
import who.tmap.toolkit.shape.LabelShape;
import who.tmap.toolkit.shape.MapShape;
import who.tmap.toolkit.shape.PolygonShape;
import who.tmap.toolkit.shape.annotation.BackgroundImageShape;
import who.tmap.toolkit.shape.annotation.LabelsListShape;

public class ThematicMapDAOImpl extends BaseDAOImpl implements ThematicMapDAO {

    private static final String VERSION ="1.0";	
    
    private static final DAOFactory daof =DAOFactory.getInstance();
    private static final CDDAOFactory cddaof =CDDAOFactory.getInstance();
	
    public BizObject loadXml( Element elt ) throws TMapDAOException {
        ThematicMap thematicMap =null;

        try {
        	thematicMap =(ThematicMap)bof.get( BizObjectFactory.THEMATIC_MAP );
        	
	        String version =elt.getAttributeValue("version");
        	
        	BaseMapDAO baseMapDao =(BaseMapDAO)daof.get( BizObjects.BASE_MAP );
        	BaseMap baseMap =(BaseMap)baseMapDao.loadXml( elt.getChild( BaseMapDAO.ROOT_ELT ) );
        	thematicMap.setBaseMap( baseMap );
        	if ( baseMap.getFile() != null ) {
        		thematicMap.setBaseMapLinkedFileName( baseMap.getFile().getAbsolutePath() );
        		thematicMap.setLinkedFile( true );
        		baseMap.setFile( null );
        	}
        	
        	DataDAO dataDao =(DataDAO)daof.get( BizObjects.ATTRS );
        	Attrs data =(Attrs)dataDao.loadXml( elt.getChild( DataDAO.ROOT_ELT ) );
        	thematicMap.setData( data );
        	if ( data.getFile() != null ) {
        		thematicMap.setDataLinkedFileName( data.getFile().getAbsolutePath() );
        		thematicMap.setLinkedFile( true );
        		data.setFile( null );
        	}        	
        	
        	CartographicDisplay cd =loadCartographicDisplay( elt.getChild( CartographicDisplayDAO.ROOT_ELT ) );
        	thematicMap.setCartographicDisplay( cd ); 
        	if ( cd.getFile() != null ) {
        		thematicMap.setCartographicDisplayLinkedFileName( cd.getFile().getAbsolutePath() );
        		thematicMap.setLinkedFile( true );
        		cd.setFile( null );
        	}            	
        	
        	AnnotationsDAO annotationsDao =(AnnotationsDAO)daof.get( BizObjects.ANNOTATIONS );
        	Annotations annotations =(Annotations)annotationsDao.loadXml( elt.getChild( AnnotationsDAO.ROOT_ELT ) );
        	thematicMap.setAnnotations( annotations );
        	if ( annotations.getFile() != null ) {
        		thematicMap.setAnnotationsLinkedFileName( annotations.getFile().getAbsolutePath() );
        		thematicMap.setLinkedFile( true );
        		annotations.setFile( null );
        	}         
        	
        	// Keep the background image file link if necessary
        	for( MapShape mapShape : annotations.getGraphics() ) {
        		if ( mapShape instanceof BackgroundImageShape ) {
        			String fileName =null;
        			if ( ((BackgroundImageShape)mapShape).getFile() != null ) {
        				fileName =((BackgroundImageShape)mapShape).getFile().getAbsolutePath();
        				thematicMap.setLinkedFile( true );
        			}
        			thematicMap.setBackgroundImageLinkedFileName( fileName );
        		}
        	}
        	
        	applyAnnotationsToBaseMap( baseMap, annotations );
        	
        } catch( Exception e ) {
        	throw new TMapDAOException( e );
        }
        
        return thematicMap;
     }
    
    private void applyAnnotationsToBaseMap( BaseMap baseMap, Annotations annotations ) {
    	Map<String, MapShape> lls =new TreeMap<String, MapShape>();
    	
    	for( MapShape mapShape : annotations.getGraphics() ) {
    		if ( mapShape instanceof LabelsListShape ) {
    			lls.put( ((LabelsListShape)mapShape).getName(), mapShape );
    		} 
    			
    		baseMap.getShapes().add( mapShape );
    	}
    	
    	for( MapShape mapShape : baseMap.getShapes() ) {
    		if ( mapShape instanceof PolygonShape ) {
    			LabelShape labelShape =((PolygonShape)mapShape).getLabelShape();
    			LabelsListShape labelsList =labelShape.getLabelsList();
    			if ( labelsList != null ) {
    				labelShape.setLabelsList( (LabelsListShape)lls.get( labelsList.getName() ) );
    			}
    		} 
    	}

    }
    
	public BizObject load(String fileName) throws TMapDAOException {
        ThematicMap thematicMap =null;

        try {
            Element rootElt =getRootElement( fileName );
	        thematicMap =(ThematicMap)loadXml( rootElt );
	        thematicMap.setFile( new File( fileName ) );
        } catch( Exception e ) {
            throw new TMapDAOException( e );
        }
        
        return thematicMap;
	}

	public Element saveXml(BizObject object) throws TMapDAOException {
		ThematicMap thematicMap =(ThematicMap)object;
		
        Element rootElt =new Element( "TMapThematicMap" );
        rootElt.setAttribute( "version", VERSION );
        
    	BaseMapDAO baseMapDao =(BaseMapDAO)daof.get( BizObjects.BASE_MAP );        
        
        Element baseMapElt;
        if ( thematicMap.isLinkedFile() && thematicMap.getBaseMapLinkedFileName() != null ) {
        	baseMapElt =buildLinkedFileElt( BaseMapDAO.ROOT_ELT, thematicMap.getBaseMapLinkedFileName() );
/*        	if ( thematicMap.getBaseMapLinkedFileName().toUpperCase().endsWith( FileExtensions.SHAPE_FILE_EXT.toUpperCase() ) ) {
        		baseMapElt.setAttribute( "dbasePolygonIdx", String.valueOf( thematicMap.getBaseMap().getDbaseJoinIdx() ) );
        	}*/
        	baseMapDao.saveDbaseJoinId( baseMapElt, thematicMap.getBaseMap().getDbaseJoinIdx() );
        	
        } else {

        	baseMapElt =baseMapDao.saveXml( thematicMap.getBaseMap() );
        }
        rootElt.addContent( baseMapElt );
        
    	DataDAO tableDao =(DataDAO)daof.get( BizObjects.ATTRS );
        
        Element tableElt;
        if ( thematicMap.isLinkedFile() && thematicMap.getDataLinkedFileName() != null ) {  
        	tableElt =buildLinkedFileElt( DataDAO.ROOT_ELT, thematicMap.getDataLinkedFileName() );

        	tableDao.saveDsProperties( tableElt, thematicMap.getData() );
        } else {
        	tableElt =tableDao.saveXml( thematicMap.getData() );
        }
        rootElt.addContent( tableElt );
        
        Element cdElt;
        if ( thematicMap.isLinkedFile() && thematicMap.getCartographicDisplayLinkedFileName() != null ) {
        	cdElt =buildLinkedFileElt( CartographicDisplayDAO.ROOT_ELT, thematicMap.getCartographicDisplayLinkedFileName() );
        } else {
	        int type =thematicMap.getCartographicDisplay() != null 
	        				? thematicMap.getCartographicDisplay().getType()
	        				: CDTypes.PROPORTIONAL_SYMBOLS;
	    	CartographicDisplayDAO cdDao =(CartographicDisplayDAO)cddaof.get( type );
	    	cdElt =cdDao.saveXml( thematicMap.getCartographicDisplay() );
        }
    	rootElt.addContent( cdElt );
    	
    	Annotations ann =thematicMap.getAnnotations();
    	ann.setGraphics( thematicMap.getBaseMap().getShapes() );

        Element annotationsElt;
        if ( thematicMap.isLinkedFile() && thematicMap.getAnnotationsLinkedFileName() != null ) {
        	annotationsElt =buildLinkedFileElt( AnnotationsDAO.ROOT_ELT, thematicMap.getAnnotationsLinkedFileName() );
        } else {
        	// Remove the background image file when saved as a .tma
        	// or set it when saved as a .tml
    		for( MapShape mapShape : thematicMap.getAnnotations().getGraphics() ) {
    			if ( mapShape instanceof BackgroundImageShape ) {
    				((BackgroundImageShape)mapShape).setFile( 
    						thematicMap.isLinkedFile() && thematicMap.getBackgroundImageLinkedFileName() != null 
    								? new File( thematicMap.getBackgroundImageLinkedFileName() )
    								: null);
    				break;
    			}
    		}
        	
        	AnnotationsDAO annotationsDao =(AnnotationsDAO)daof.get( BizObjects.ANNOTATIONS );
        	annotationsElt =annotationsDao.saveXml( thematicMap.getAnnotations() );
        }
        rootElt.addContent( annotationsElt );
                
		return rootElt;
	}
	
	private CartographicDisplay loadCartographicDisplay( Element elt ) throws TMapDAOException {
		CartographicDisplay cd =null;
		CartographicDisplayDAO cdDao =null;
		
		if ( elt.getChild( "PointBasic" ) != null ) {
			cdDao =cddaof.get( CDTypes.POINT_BASIC );
		} else if ( elt.getChild( "PointDataDrivenSize" ) != null ) {
			cdDao =cddaof.get( CDTypes.POINT_DATA_DRIVEN_SIZE );
		} else if ( elt.getChild( "PointDataDrivenSymbol" ) != null ) {
			cdDao =cddaof.get( CDTypes.POINT_DATA_DRIVEN_SYMBOL );	
		} else if ( elt.getChild( "PointDataDrivenSymbolAndSize" ) != null ) {
			cdDao =cddaof.get( CDTypes.POINT_DATA_DRIVEN_SYMBOL_AND_SIZE );				
		} else if ( elt.getChild( "ColorPattern" ) != null ) {
			cdDao =cddaof.get( CDTypes.COLOR_PATTERN );
		} else if ( elt.getChild( "ProportionalSymbols" ) != null ) {
			cdDao =cddaof.get( CDTypes.PROPORTIONAL_SYMBOLS );
		} else if ( elt.getChild( "RandomDotDensity" ) != null ) {
			cdDao =cddaof.get( CDTypes.DOT_DENSITY );
		} else {
		    Attribute linkElt =elt.getAttribute( "linkFile" ); 
		    if ( linkElt != null ) {
		    	String fileName =linkElt.getValue();
		    	if ( fileName != null && !fileName.equals("") ) {
		    		Element rootElt;
					try {
						rootElt = getRootElement( fileName );
					} catch (Exception e) {
						throw new TMapDAOException( e );
					}
		    		cd =loadCartographicDisplay( rootElt );
		    		cd.setFile( new File(fileName) );
		    	}
		    }
		}
		
		if ( cdDao != null ) {
			cd =(CartographicDisplay)cdDao.loadXml( elt );
		}
		
		return cd;
	}

}
